package cn.nju.seg.atg.util;

import java.util.ArrayList;
import java.util.List;
import cn.nju.seg.atg.model.SimpleCFGNode;
import cn.nju.seg.atg.parse.Builder;

public class CFGPath {

	/**
	 * 一条路径
	 */
	private List<SimpleCFGNode> path;
	
	/**
	 * 路径中需要的辅助变量个数
	 */
	private int numOfAuxiliaryVars;
	
	/**
	 * 路径中路径谓词的个数
	 */
	private int numOfPathPredicates;
	
	/**
	 * 当前路径的最优输入参数
	 * 即该输入参数所能覆盖的节点数最多
	 */
	private double[] optimalParams;
	
	/**
	 * 当前最优输入参数覆盖到的节点数
	 */
	private int numOfCoveredNodes;
	
	/**
	 * 最优输入参数覆盖到的最远节点名称
	 */
	private String endCoveredNodeName;
	
	/**
	 * 判断当前路径是否已被覆盖
	 * true-是  false-否
	 */
	private boolean isCovered;
	
	/**
	 * 无参构造函数
	 */
	public CFGPath()
	{
		path = new ArrayList<SimpleCFGNode>();
		numOfAuxiliaryVars = 0;
		numOfPathPredicates = 0;
		numOfCoveredNodes = 0;
		isCovered = false;
	}
	
	/**
	 * 获取路径中需要的辅助变量个数
	 * @return
	 */
	public int getNumOfAuxiliaryVars(){
		return this.numOfAuxiliaryVars;
	}
	
	/**
	 * 设置路径中需要的辅助变量个数
	 * @return
	 */
	public void setNumOfAuxiliaryVars(int num){
		this.numOfAuxiliaryVars = num;
	}
	
	/**
	 * 获取路径中路径谓词的个数
	 * @return
	 */
	public int getNumOfPathPredicates(){
		return this.numOfPathPredicates;
	}
	
	/**
	 * 设置路径中路径谓词的个数
	 * @return
	 */
	public void setNumOfPathPredicates(int num){
		this.numOfPathPredicates = num;
	}
	
	/**
	 * 获取当前最优输入参数
	 * @return
	 */
	public double[] getOptimalParams()
	{
		return this.optimalParams;
	}
	
	/**
	 * 设置当前最优输入参数
	 * @param params
	 */
	public void setOptimalParams(double[] params)
	{
		this.optimalParams = new double[params.length];
		for (int i=0; i<params.length; i++)
		{
			this.optimalParams[i] = params[i];
		}
	}
	
	/**
	 * 设置最优参数覆盖到的节点数
	 * @return
	 */
	public int getNumOfCoveredNodes() {
		return numOfCoveredNodes;
	}

	/**
	 * 获取最优参数覆盖到的节点数
	 * @param numOfCoveredNodes
	 */
	public void setNumOfCoveredNodes(int numOfCoveredNodes) {
		this.numOfCoveredNodes = numOfCoveredNodes;
	}

	/**
	 * 获取最优参数覆盖到的最远节点的名称
	 * @return
	 */
	public String getEndCoveredNodeName() {
		return endCoveredNodeName;
	}

	/**
	 * 设置最优参数覆盖到的最远节点的名称
	 * @param endCoveredNode
	 */
	public void setEndCoveredNodeName(String endCoveredNodeName) {
		this.endCoveredNodeName = endCoveredNodeName;
	}

	/**
	 * 获取覆盖结果
	 * @return
	 */
	public boolean isCovered() {
		return isCovered;
	}

	/**
	 * 设置覆盖结果
	 * @param isCovered
	 */
	public void setCovered(boolean isCovered) {
		this.isCovered = isCovered;
	}

	/**
	 * 复制当前路径
	 * @return 一条路径
	 */
	public CFGPath clonePath()
	{
		CFGPath path = new CFGPath();
		
		int pathSize = this.path.size();
		for (int i=0; i<pathSize; i++)
		{
			SimpleCFGNode snode = new SimpleCFGNode(this.path.get(i).getName(),this.path.get(i).getType(),this.path.get(i).getConstraint(),this.path.get(i).isTrue());
			path.addNode(snode);
		}
		
		path.setNumOfAuxiliaryVars(this.numOfAuxiliaryVars);
		if (this.optimalParams != null)
			path.setOptimalParams(this.optimalParams);
		path.setCovered(this.isCovered);
		path.setEndCoveredNodeName(this.endCoveredNodeName);
		path.setNumOfCoveredNodes(this.numOfCoveredNodes);
		
		return path;
	}
	
	/**
	 * 添加一个SimpleCFGNode节点
	 * @param node
	 */
	public void addNode(SimpleCFGNode node)
	{
		this.path.add(node);
	}
	
	/**
	 * 按参数添加普通节点
	 * @param nodeName
	 * @param nodeType
	 */
	public void addNormalNode(String nodeName, int nodeType)
	{
		int pathSize = path.size();
		int index = -1;
		for (int i=0; i<pathSize; i++)
		{
			if(path.get(i).getName().equals(nodeName))
			{
				index = i;
				break;
			}
		}
		if (index==-1 || index==pathSize)
		{
			SimpleCFGNode tempNode = new SimpleCFGNode();
			tempNode.setName(nodeName);
			tempNode.setType(nodeType);
			path.add(tempNode);
		}
	}
	
	/**
	 * 按参数添加分支节点
	 * @param nodeName
	 * @param nodeType
	 * @param constraintExpression
	 * @param c
	 */
	public void addBranchNode(String nodeName, int nodeType, String atomicConstraintExpression, double v)
	{
		int pathSize = path.size();
		//判断nodeName是否已在path中
		int index = -1;
		for (int i=0; i<pathSize; i++)
		{
			if(path.get(i).getName().equals(nodeName))
			{
				index = i;
				break;
			}
		}
		//根据index的情况，在path中插入node
		if (index==-1)
		{
			SimpleCFGNode tempNode = new SimpleCFGNode();
			tempNode.setName(nodeName);
			tempNode.setType(nodeType);
			tempNode.addValue(atomicConstraintExpression, v);
			path.add(tempNode);
		}
		else if (index>=0 && index<pathSize)
		{
			for (int i=0; i<pathSize; i++)
			{
				if (path.get(i).getName().equals(nodeName))
				{
					path.get(i).addValue(atomicConstraintExpression, v);
				}
			}
		}
	}

	
	/**
	 * 找出当前路径覆盖到目标路径的部分
	 * @param targetPath
	 * @return 一条路径片段
	 */
	public CFGPath getCoveredPath(CFGPath targetPath)
	{
		CFGPath coveredPath = new CFGPath();
		
		SimpleCFGNode tempNode = new SimpleCFGNode();
		
		int pathSize = this.path.size();
		int targetPathSize = targetPath.getPath().size();
		for (int i=0; i<pathSize; i++)
		{
			if (i < targetPathSize)
			{
				if (this.path.get(i).getName().equals(targetPath.getPath().get(i).getName()))
				{
					tempNode = this.path.get(i);
					tempNode.setConstraint(targetPath.getPath().get(i).getConstraint());
					tempNode.setTrue(targetPath.getPath().get(i).isTrue());
					tempNode.setType(targetPath.getPath().get(i).getType());
					coveredPath.addNode(tempNode);
				}
				else
				{
					break;
				}
			}
		}
		
		coveredPath.setEndCoveredNodeName(coveredPath.getEndNodeName());
		coveredPath.setNumOfCoveredNodes(coveredPath.getPath().size());
		coveredPath.setOptimalParams(Builder.optimalParams);
		
		return coveredPath;
	}
	
	/**
	 * 更新覆盖到目标路径的最长路径片段
	 * @param newPath
	 */
	public void update(CFGPath newPath)
	{
		int pathSize = this.path.size();
		int newPathSize = newPath.getPath().size();
		for (int i=pathSize; i<newPathSize; i++)
		{
			this.addNode(newPath.getPath().get(i));
		}
			
		this.setOptimalParams(Builder.optimalParams);
		this.setEndCoveredNodeName(newPath.getEndNodeName());
		this.setNumOfCoveredNodes(newPathSize);

	}
	
	/**
	 * 返回末尾节点的名称
	 * @return 节点名称
	 */
	public String getEndNodeName()
	{
		int pathSize = this.path.size();
		return this.path.get(pathSize-1).getName();
	}
	
	/**
	 * 判断当前路径是否是目标路径
	 * @param targetPath
	 * @return true|false
	 */
	public boolean isTargetPath(CFGPath targetPath)
	{
		if (this.getEndNodeName().equals(targetPath.getEndNodeName()))
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	/**
	 * 判断path是否于myPath相同
	 * @param path
	 * @return
	 */
	public boolean isEqual(List<SimpleCFGNode> myPath)
	{
		if (path.size() != myPath.size())
		{
			return false;
		}
		else
		{
			int size = path.size();
			for (int i=0; i<size; i++)
			{
				if (!path.get(i).isEqual(myPath.get(i)))
				{
					return false;
				}
			}
		}
		return true;
	}
	
	/**
	 * 获取可用取值区间
	 * @return 可用取值区间
	 */
/*	public List<Interval> getEffectiveIntevalList()
	{
		List<Interval> effectiveIntervalList = new ArrayList<Interval>();
		//初始化effectiveIntervalList为全集
		Interval initialInterval = Builder.maxInterval();
		effectiveIntervalList.add(initialInterval);
		
		List<Interval> tempIntervalList;
		SimpleCFGNode node = new SimpleCFGNode();
		
		int pathSize = this.path.size();
		for (int i=0; i<pathSize; i++)
		{
			if (this.path.get(i).isBranchNode())
			{
				tempIntervalList = this.path.get(i).getEffectiveIntervalList();
				List<Interval> temp = node.getIntersection(effectiveIntervalList, tempIntervalList);
				effectiveIntervalList = temp;
			}
		}
		
		return effectiveIntervalList;
	}


	/**
	 * 获取新的可用输入数据集合
	 * @return 输入数据集合
	 */
/*  public List<Double> getNewParameterList(int paramIndex)
	{
		List<Double> newParameterList = new ArrayList<Double>();
		
		List<Interval> effectiveIntervalList = this.getEffectiveIntevalList();
		
		if (effectiveIntervalList != null && effectiveIntervalList.size() != 0)
		{
			int numOfNewParams = 0;
			int effectiveIntervalListSize = effectiveIntervalList.size();
			
			for (int i=0; i<effectiveIntervalListSize; i++)
			{
				double newParameter = effectiveIntervalList.get(i).getNewCoodinate();
				newParameterList.add(newParameter);
				numOfNewParams++;
			}
			
			// 如果衍生出的新参数不多于2个，则以当前衍生池边界值向外扩展出新参数
			if (numOfNewParams <= 2)
			{
				double autoIncreased = Builder.maxInterval().getLeftBoundary() - Math.random()*ATG.MAX_STEP[paramIndex];
				Builder.autoIncreasedParameterList.add(autoIncreased);	//标记为向外扩展时生成的
				newParameterList.add(autoIncreased);
				
				autoIncreased = Builder.maxInterval().getRightBoundary() + Math.random()*ATG.MAX_STEP[paramIndex];
				Builder.autoIncreasedParameterList.add(autoIncreased);	//标记为向外扩展时生成的
				newParameterList.add(autoIncreased);
			}
		}
		else
		{
			double autoIncreased = Builder.maxInterval().getLeftBoundary() - Math.random()*ATG.MAX_STEP[paramIndex];
			Builder.autoIncreasedParameterList.add(autoIncreased);	//标记为向外扩展时生成的
			newParameterList.add(autoIncreased);
			autoIncreased = Builder.maxInterval().getRightBoundary() + Math.random()*ATG.MAX_STEP[paramIndex];
			Builder.autoIncreasedParameterList.add(autoIncreased);	//标记为向外扩展时生成的
			newParameterList.add(autoIncreased);
		}
		return newParameterList;
	}
*/
	public List<SimpleCFGNode> getPath() {
		return path;
	}

	public void setPath(List<SimpleCFGNode> path) {
		this.path = path;
	}

	/**
	 * 显示该路径上所有分支节点的线性拟合函数
	 */
/*
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void showCLF(int pathIndex, double effectiveValue)
	{
		LineChart chart = new LineChart();
		int pathSize = path.size();
		Iterator iterator = null;
		for (int i=0; i<pathSize; i++)
		{
			if (path.get(i).getType() == ConstantValue.BRANCH_IF || path.get(i).getType() == ConstantValue.BRANCH_FOR)
			{
				iterator = path.get(i).getValues().entrySet().iterator();
				while (iterator.hasNext())
				{
					Map.Entry entry = (Map.Entry)iterator.next();
					chart.showLineChart((pathIndex+1)+"."+i+" "+(String)entry.getKey(), (List<Coodinate>)entry.getValue(), Builder.autoIncreasedParameterList, effectiveValue);
				}
			}
		}
	}
	
	/**
	 * 显示该路径上表达式为constraint的分支节点的线性拟合函数
	 */
/*
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void showCLF(int pathIndex, double effectiveValue, String constraint)
	{
		LineChart chart = new LineChart();
		int pathSize = path.size();
		Iterator iterator = null;
		for (int i=0; i<pathSize; i++)
		{
			if (path.get(i).getType() == ConstantValue.BRANCH_IF || path.get(i).getType() == ConstantValue.BRANCH_FOR)
			{
				iterator = path.get(i).getValues().entrySet().iterator();
				while (iterator.hasNext())
				{
					Map.Entry entry = (Map.Entry)iterator.next();
					if (constraint.equals((String)entry.getKey()))
					{
						chart.showLineChart((pathIndex+1)+"."+i+" "+(String)entry.getKey(), (List<Coodinate>)entry.getValue(), Builder.autoIncreasedParameterList, effectiveValue);
					}
				}
			}
		}
	}
*/
}
